﻿//业务层只能访问仓储
using Jst.Application.Contracts.Dto.SignIn;
using Jst.Application.Contracts.IApplication.SignIn;
using Jst.Core;
using Jst.Core.Configuration;
using Jst.Core.jwt;
using Jst.Core.Redis;
using Jst.Core.Utility;
using Jst.Domain;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using SqlSugar;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;

namespace Jst.Application.SignIn
{
    public class AuthServices : IAuthServices
    {
        private readonly DbManager _dbManager;
        private readonly PermissionRequirement _permissionRequirement;
        private readonly IRedisOperationRepository _redisOperationRepository;
        private readonly IHttpContextAccessor _httpContextAccessor;

        public AuthServices(DbManager dbManager
            , PermissionRequirement permissionRequirement
            , IRedisOperationRepository redisOperationRepository
            , IHttpContextAccessor httpContextAccessor)
        {
            _dbManager = dbManager;
            _permissionRequirement = permissionRequirement;
            _redisOperationRepository = redisOperationRepository;
            _httpContextAccessor = httpContextAccessor;
        }

        private ISqlSugarClient DbBaseClient => _dbManager.DefaultDb;

        /// <summary>
        /// 获取签名
        /// </summary>
        /// <param name="token">签名</param>
        /// <param name="secretKey">密钥</param>
        /// <returns></returns>
        public async Task<ApiResult> GetSignature(string token, string secretKey)
        {
            var result = new ApiResult();

            // 验证 token 和 secretKey 是否正确
            if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(secretKey) ||
                !token.Equals(AppSettingsConstVars.JwtConfigAudience) || !secretKey.Equals(AppSettingsConstVars.JwtConfigSecretKey))
            {
                result.message = "密钥错误";
                return result;
            }

            // 将 secretKey 和 token 转换为字节数组
            byte[] keyBytes = Encoding.UTF8.GetBytes(secretKey);
            byte[] dataBytes = Encoding.UTF8.GetBytes(token);

            byte[] signatureBytes;

            // 使用 HMACSHA256 算法生成签名
            try
            {
                using (var hmac = new HMACSHA256(keyBytes))
                {
                    signatureBytes = hmac.ComputeHash(dataBytes);
                }
            }
            catch (Exception ex)
            {
                result.message = $"签名生成失败: {ex.Message}";
                return result;
            }

            // 将签名转换为字符串格式（去除 "-" 分隔符）
            string signature = BitConverter.ToString(signatureBytes).Replace("-", string.Empty);

            // 设置返回结果
            result.code = 0;
            result.success = true;
            result.message = "签名获取成功";
            result.data = signature;

            return result;
        }

        /// <summary>
        /// 获取jwt令牌
        /// </summary>
        /// <param name="signature"></param>
        /// <returns></returns>
        public async Task<ApiResult> GetJwtToken(LoginInput input)
        {
            var result = new ApiResult();

            // 检查输入的账号和密码是否为空
            if (string.IsNullOrEmpty(input.account) || string.IsNullOrEmpty(input.password))
            {
                result.message = "账号或密码不能为空";
                return result;
            }

            // 对密码进行安全的哈希处理，建议使用 bcrypt 或类似算法
            input.password = CommonHelper.Md5For32(input.password);

            // 从数据库中获取用户账户信息
            var user = await GetAccount(input.account, input.password);

            // 验证用户是否存在且未被禁用
            if (user == null)
            {
                result.message = "用户不存在或密码错误";
                return result;
            }

            // 将用户 ID 存储到 Redis，设置过期时间
            await _redisOperationRepository.StringSetAsync($"user:{user.Id}:session", user.Id.ToString(), TimeSpan.FromSeconds(30));

            //获取用户角色权限
            var userRoles = await GetUserRoleNameStr(input.account, input.password);

            // 创建用户的声明集合
            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.Name, user.LoginName),
                new Claim(JwtRegisteredClaimNames.Jti, user.Id.ToString()),
                //new Claim("TenantId", user.TenantId.ToString()),
                new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString()),
                new Claim(ClaimTypes.Expiration, DateTime.UtcNow.AddSeconds(_permissionRequirement.Expiration.TotalSeconds).ToString())
            };
            claims.AddRange(userRoles.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));

            // 创建身份主体
            var identity = new ClaimsIdentity(JwtBearerDefaults.AuthenticationScheme);
            identity.AddClaims(claims);

            // 生成 JWT 令牌
            var token = JwtToken.BuildJwtToken(claims.ToArray(), _permissionRequirement, AppSettingsConstVars.JwtConfigSecretKey);

            result.code = 0;
            result.success = true;
            result.data = token;
            result.message = "认证成功";

            return result;
        }

        /// <summary>
        /// 请求刷新Token（以旧换新）
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public async Task<ApiResult> RefreshToken(string token = "")
        {
            var jwtStr = string.Empty;
            var result = new ApiResult();

            if (string.IsNullOrEmpty(token))
                return result.FailedResult(500, "token无效，请重新登录！");

            var tokenModel = JwtToken.SerializeJwt(token);

            if (tokenModel != null && JwtToken.customSafeVerify(token) && tokenModel.Uid > 0)
            {
                var user = await GetUserInfoByIdAsync(tokenModel.Uid);
                var value = _httpContextAccessor.HttpContext.User.Claims.SingleOrDefault(s => s.Type == JwtRegisteredClaimNames.Iat)?.Value;
                if (value != null && user.CriticalModifyTime > value.ObjectToDate())
                {
                    return result.FailedResult(500, "很抱歉,授权已失效,请重新授权！");
                }

                if (user != null && !(value != null && user.CriticalModifyTime > value.ObjectToDate()))
                {
                    var userRoles = await GetUserRoleNameStr(user.LoginName, user.LoginPWD);
                    //如果是基于用户的授权策略，这里要添加用户;如果是基于角色的授权策略，这里要添加角色
                    var claims = new List<Claim>
                    {
                        new Claim(ClaimTypes.Name, user.LoginName),
                        new Claim(JwtRegisteredClaimNames.Jti, tokenModel.Uid.ObjectToString()),
                        new Claim(JwtRegisteredClaimNames.Iat,DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString()),
                         new Claim(ClaimTypes.Expiration, DateTime.UtcNow.AddSeconds(_permissionRequirement.Expiration.TotalSeconds).ToString())
                    };
                    claims.AddRange(userRoles.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));

                    //用户标识
                    var identity = new ClaimsIdentity(JwtBearerDefaults.AuthenticationScheme);
                    identity.AddClaims(claims);

                    var refreshToken = JwtToken.BuildJwtToken(claims.ToArray(), _permissionRequirement, AppSettingsConstVars.JwtConfigSecretKey);
                    return result.Success("获取成功", refreshToken);
                }
            }

            return result.FailedResult(500, "认证失败！");
        }

        /// <summary>
        /// 获取登录信息
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public async Task<ApiResult> SingleLogin(string token, double expires_in)
        {
            var result = new ApiResult();

            var tokenModel = JwtToken.SerializeJwt(token);

            var user = await GetUserInfoByIdAsync(tokenModel.Uid);

            var query = await GetLoginMenue(tokenModel.Uid);

            string jsonString = JsonConvert.SerializeObject(query);

            var menulist = JsonConvert.DeserializeObject<List<NavigationBar>>(jsonString);

            var res = new SingleLoginUserModel()
            {
                UserId = user.Id.ToString(),

                UserName = user.Name,

                IsExpired = true,

                expires_in = expires_in,

                Token = token,

                UserInfo = user,

                RoleList = menulist
            };

            result.data = res;
            return result;
        }

        /// <summary>
        /// 获取路由树
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public async Task<ApiResult> GetLoginMenue(string token)
        {
            var result = new ApiResult();
            var tokenModel = JwtToken.SerializeJwt(token);
            if (tokenModel != null)
            {
                var user = await GetUserInfoByIdAsync(tokenModel.Uid);
                if (user != null)
                {
                    var query = await GetLoginMenue(user.Id);

                    string jsonString = JsonConvert.SerializeObject(query);

                    var menulist = JsonConvert.DeserializeObject<List<NavigationBar>>(jsonString);
                    result.data = menulist;
                    result.message = "获取成功";
                    result.code = 200;
                    result.success = true;
                    return result;
                }
            }

            return result.FailedResult(500, "菜单获取失败！");
        }



        #region 

        /// <summary>
        /// 获取用户账号
        /// </summary>
        /// <param name="account"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public async Task<SysUserInfo> GetAccount(string account, string password)
        {
            return await DbBaseClient.Queryable<SysUserInfo>().FirstAsync(_ => _.LoginName == account && _.LoginPWD == password && _.IsDeleted == false);
        }

        /// <summary>
        /// 获取用户角色权限
        /// </summary>
        /// <param name="account"></param>
        /// <param name="password"></param>
        /// <returns></returns>
        public async Task<string> GetUserRoleNameStr(string account, string password)
        {
            string roleName = "";
            var user = await DbBaseClient.Queryable<SysUserInfo>().Where(_ => _.LoginName == account && _.LoginPWD == password && _.IsDeleted == false).FirstAsync();
            var roleList = await DbBaseClient.Queryable<Role>().Where(_ => _.IsDeleted == false).ToListAsync();
            var userRoles = await DbBaseClient.Queryable<UserRole>().Where(_ => _.UserId == user.Id).ToListAsync();
            if (userRoles.Count > 0)
            {
                var arr = userRoles.Select(ur => ur.RoleId.ObjectToString()).ToList();
                var roles = roleList.Where(d => arr.Contains(d.Id.ObjectToString()));
                roleName = string.Join(',', roles.Select(r => r.Name).ToArray());
            }
            return roleName;

        }

        /// <summary>
        /// 根据Id获取用户信息
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public async Task<SysUserInfo> GetUserInfoByIdAsync(long Id)
        {
            return await DbBaseClient.Queryable<SysUserInfo>().Where(_ => _.Id == Id && _.IsDeleted == false).FirstAsync();
        }

        /// <summary>
        /// 获取角色列表
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public async Task<object> GetRoleListAsync(long Id)
        {
            var query = await DbBaseClient.Queryable<Role>()
                       .LeftJoin<UserRole>((a, b) => a.Id == b.RoleId)
                       .LeftJoin<SysUserInfo>((a, b, c) => b.UserId == c.Id)
                       .Where((a, b, c) => c.IsDeleted == false && a.Enabled == true)
                       .GroupBy((a, b, c) => new { a.Id, a.Description, a.Name })
                       .Select((a, b, c) => new
                       {
                           AppID = a.Id.ToString(),
                           RoleCode = a.Description,
                           RoleName = a.Name,
                           RoleType = ""
                       }).ToListAsync();

            return query;
        }

        /// <summary>
        /// 获取路由树
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public async Task<object> GetLoginMenue(long Id)
        {
            // 获取用户角色ID
            var roleIds = await DbBaseClient.Queryable<UserRole>()
                        .Where(_ => _.IsDeleted == false && _.UserId == Id)
                        .Select(_ => _.RoleId)
                        .Distinct()
                        .ToListAsync();

            if (!roleIds.Any())
                return null;

            // 获取角色权限ID
            var pids = await DbBaseClient.Queryable<RoleModulePermission>()
                      .Where(_ => _.IsDeleted == false && roleIds.Contains(_.RoleId))
                      .Select(_ => _.PermissionId)
                      .Distinct()
                      .ToListAsync();

            if (!pids.Any())
                return null;

            // 获取角色权限模块
            var rolePermissionModules = await DbBaseClient.Queryable<Permission>()
                                        .Where(_ => pids.Contains(_.Id) && _.IsButton == false)
                                        .OrderBy(c => c.OrderSort).ToListAsync();

            // 递归构建权限树的方法
            List<dynamic> BuildPermissionTree(List<Permission> permissions, long parentId)
            {
                return permissions
                    .Where(item => item.Pid == parentId)
                    .OrderBy(item => item.OrderSort)
                    .Select(item => new
                    {
                        id = item.Id,
                        name = item.Name,
                        pid = item.Pid,
                        order = item.OrderSort,
                        path = item.Code,
                        iconCls = item.Icon,
                        Func = item.Func,
                        IsHide = item.IsHide.ObjectToBool(),
                        IsButton = item.IsButton.ObjectToBool(),
                        meta = new
                        {
                            requireAuth = true,
                            title = item.Name,
                            NoTabPage = item.IsHide.ObjectToBool(),
                            keepAlive = item.IskeepAlive.ObjectToBool()
                        },
                        children = BuildPermissionTree(permissions, item.Id) // 使用 item.Id
                    })
                    .Cast<dynamic>() // 将匿名对象转换为 dynamic
                    .ToList();
            }

            // 构建权限树
            return BuildPermissionTree(rolePermissionModules, 0);
        }

        /// <summary>
        /// 获取角色权限Id
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public async Task<List<long>> GetUserRoleIds(long Id)
        => await DbBaseClient.Queryable<UserRole>().Where(_ => _.UserId == Id).Select(_ => _.RoleId).Distinct().ToListAsync();


        #endregion
    }
}
